package com.hxd.otc.utils;

import com.hxd.otc.module.wallet.bean.BasePayBean;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
 * Created by lzy on 2018/8/21 0021.
 * description ${支付工具}
 */
public class PayUtils {

    public static final String PAY_EXTRA_API_KEY = "apiKey";
    public static final String PAY_EXTRA_DATA = "data";
    public static final String PAY_EXTRA_NONCE = "nonce";
    public static final String PAY_EXTRA_SIGNATURE = "signature";
    public static final String PAY_EXTRA_TIMESTAMP = "timestamp";

    /**
     * 对数据体进行加密
     *
     * @param dataJson 需要被加密的数据json字符串
     */
    public static String encodeData(String dataKey, String dataJson) {
        try {
            return AESUtils.encrypt(dataJson, AESUtils.restoreSecretKey(dataKey.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成支付参数
     *
     * @param basePayBean
     * @return
     */
    public static TreeMap<String, String> generatePayData(BasePayBean basePayBean) {
        TreeMap<String, String> params = new TreeMap<>();
        params.put(PAY_EXTRA_API_KEY, basePayBean.getApiKey());
        params.put(PAY_EXTRA_DATA, encodeData(basePayBean.getDataKey(), GsonUtil.toJson(basePayBean.getPayInfoBean())));
        String timestamp = getTimestamp().toString();
        params.put(PAY_EXTRA_NONCE, timestamp);
        params.put(PAY_EXTRA_TIMESTAMP, timestamp);
        params.put(PAY_EXTRA_SIGNATURE, generateSignature(basePayBean.getSecretKey(), params));
        return params;
    }


    public static TreeMap<String, String> generatePayData(String apiKey, String secretKey, String dataKey, Object dataObj) {
        TreeMap<String, String> params = new TreeMap<>();
        params.put(PAY_EXTRA_API_KEY, apiKey);
        params.put(PAY_EXTRA_DATA, encodeData(dataKey, GsonUtil.toJson(dataObj)));
        String timestamp = getTimestamp().toString();
        params.put(PAY_EXTRA_NONCE, timestamp);
        params.put(PAY_EXTRA_TIMESTAMP, timestamp);
        params.put(PAY_EXTRA_SIGNATURE, generateSignature(secretKey, params));
        return params;
    }

    /**
     * 创建一个有效的签名。该方法为客户端调用，将在传入的params中添加data、apikey、timestamp、nonce、signature参数。
     *
     * @param params
     * @return
     */
    public static String generateSignature(String secretKey, TreeMap<String, String> params) {
        StringBuilder sb = new StringBuilder(1024);
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key).append('=').append(urlEncode(value)).append('&');
        }
        // remove last '&':
        sb.deleteCharAt(sb.length() - 1);
        // sign:
        Mac hmacSha256 = null;
        try {
            hmacSha256 = Mac.getInstance("HmacSHA256");
            SecretKeySpec secKey =
                    new SecretKeySpec(secretKey.getBytes(Charset.forName("UTF-8")), "HmacSHA256");
            try {
                hmacSha256.init(secKey);
            } catch (java.security.InvalidKeyException e) {
                e.printStackTrace();
            }
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("No such algorithm: " + e.getMessage());
        }
        String payload = sb.toString();
        byte[] hash = hmacSha256.doFinal(payload.getBytes(Charset.forName("UTF-8")));
        return Base64.encode(hash);
    }

    /**
     * 使用标准URL Encode编码。注意和JDK默认的不同，空格被编码为%20而不是+。
     *
     * @param s String字符串
     * @return URL编码后的字符串
     */
    public static String urlEncode(String s) {
        try {
            return URLEncoder.encode(s, "UTF-8").replaceAll("\\+", "%20");
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("UTF-8 encoding not supported!");
        }
    }

    /**
     * 获取时间戳
     */
    public static Long getTimestamp() {
        return System.currentTimeMillis() / 1000;
    }
}
